const DefaultDataAdapter = require('./../default-report/target-machine-data-adapter');
const funcsModel = require('../../../functions');
const common = require('../../../common');

class DataAdapter extends DefaultDataAdapter {
  async getFilesOverview() {
    const filesOverview = [];
    [...this.files.values()].forEach((file) => {
      if (this.version.headers.suffixes.indexOf(file.extname) >= 0) {
        return;
      }
      const extname = common.renameMongoKey(file.extname);
      const fileOverview = {
        _id: file._id,
        status: file.status,
        fileName: file.fileName,
        path: file.path,
        statementCovered: file.statementCovered[extname] || 0,
        statementTotal: file.statementTotal[extname] || 0,
        branchCovered: file.branchCovered[extname] || 0,
        branchTotal: file.branchTotal[extname] || 0,
        conditionCovered: file.conditionCovered[extname] || 0,
        conditionTotal: file.conditionTotal[extname] || 0,
        decisionCovered: file.decisionCovered[extname] || 0,
        decisionTotal: file.decisionTotal[extname] || 0,
        mcdcCovered: file.mcdcCovered[extname] || 0,
        mcdcTotal: file.mcdcTotal[extname] || 0,
        invokeCovered: file.invokeCovered[extname] || 0,
        invokeTotal: file.invokeTotal[extname] || 0,
        invokedFuncCovered: file.invokedFuncCovered[extname] || 0,
        invokedFuncTotal: file.invokedFuncTotal[extname] || 0,
        functionCount: file.functionCount,
      };
      filesOverview.push(fileOverview);
    });
    return Promise.resolve(filesOverview);
  }

  async getFunctionsOverview() {
    return Promise.resolve([...this.functions.values()].map((item) => {
      const file = this.files.get(item.fileId.toString());
      item.fileName = file.fileName;
      return item;
    }));
  }

  async getVersionOverview() {
    const sourceExts = Object.values(this.version.languages)
      .reduce((arr, item) => arr.concat(item.suffixes), []);
    const headerExts = this.version.headers.suffixes;
    const versionOverview = {
      sourceFileCount: 0,
      headerFileCount: 0,
      functionCount: this.functions.size,
      statementCovered: 0,
      statementTotal: 0,
      branchCovered: 0,
      branchTotal: 0,
      conditionCovered: 0,
      conditionTotal: 0,
      decisionCovered: 0,
      decisionTotal: 0,
      mcdcCovered: 0,
      mcdcTotal: 0,
      invokeCovered: 0,
      invokeTotal: 0,
      invokedFuncCovered: 0,
      invokedFuncTotal: 0,
      projectName: this.project ? this.project.projectName : '',
      projectId: this.version.projectId,
      _id: this.version._id,
      versionName: this.version.versionName,
    };
    [...this.files.values()].forEach((file) => {
      const fileOverCount = this.getCountOfFile(file);
      versionOverview.statementCovered += fileOverCount.statementCovered;
      versionOverview.statementTotal += fileOverCount.statementTotal;
      versionOverview.branchCovered += fileOverCount.branchCovered;
      versionOverview.branchTotal += fileOverCount.branchTotal;
      versionOverview.conditionCovered += fileOverCount.conditionCovered;
      versionOverview.conditionTotal += fileOverCount.conditionTotal;
      versionOverview.decisionTotal += fileOverCount.decisionTotal;
      versionOverview.decisionCovered += fileOverCount.decisionCovered;
      versionOverview.mcdcTotal += fileOverCount.mcdcTotal;
      versionOverview.mcdcCovered += fileOverCount.mcdcCovered;
      versionOverview.invokeTotal += fileOverCount.invokeTotal;
      versionOverview.invokeCovered += fileOverCount.invokeCovered;
      versionOverview.invokedFuncTotal += fileOverCount.invokedFuncTotal;
      versionOverview.invokedFuncCovered += fileOverCount.invokedFuncCovered;
      if (headerExts.includes(file.extname)) {
        versionOverview.headerFileCount += fileOverCount.fileCount;
      } else if (sourceExts.includes(file.extname)) {
        versionOverview.sourceFileCount += fileOverCount.fileCount;
      }
    });
    return Promise.resolve(versionOverview);
  }

  getCountOfFile(file) {
    const count = {
      statementCovered: 0,
      statementTotal: 0,
      branchCovered: 0,
      branchTotal: 0,
      conditionCovered: 0,
      conditionTotal: 0,
      decisionCovered: 0,
      decisionTotal: 0,
      mcdcCovered: 0,
      mcdcTotal: 0,
      invokeCovered: 0,
      invokeTotal: 0,
      invokedFuncCovered: 0,
      invokedFuncTotal: 0,
      fileCount: 0,
    };
    Object.keys(count).forEach((key) => {
      if (!file[key]) {
        return;
      }
      Object.keys(file[key]).forEach((ext) => {
        count[key] += file[key][ext];
      });
    });
    return count;
  }

  async getFunctionCfg(func, includeCovered = true) {
    let funcCfg = await funcsModel.getFunctionCFG(func._id, null, false);
    if (!includeCovered) {
      return funcCfg;
    }
    if (func.coveredFields) {
      funcCfg = funcsModel.mergeCfgCovered(funcCfg, func.coveredFields);
    }
    if (func.testcasesCoveredFields) {
      Object.keys(func.testcasesCoveredFields).forEach((testId) => {
        funcCfg = funcsModel.mergeCfgCovered(funcCfg, func.testcasesCoveredFields[testId], testId);
      });
    }
    return funcsModel.completeDecisionCases(funcCfg, this.version.mcdcKind);
  }
}

module.exports = DataAdapter;
